#include "DirectInput.h"
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
#include "EngineImpl.h"
namespace engine {

	InputInterface* InputInterface::QueryInterface(Engine * engine)
	{
		EngineImpl * s = reinterpret_cast<EngineImpl*>(engine);
		s->AddRef();
		return s;
	}

	DirectInput::DirectInput()
	{
		m_Keyboard = NULL;
		m_Mouse = NULL;
	}

	DirectInput::~DirectInput(void)
	{
		Shutdown();
	}

	bool DirectInput::Initialize(HWND hwnd, HINSTANCE hInst, bool exclusive)
	{
		
		if(DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&m_System, NULL) == DI_OK)
		{
			m_Keyboard = new Keyboard(m_System, hwnd);
			m_Mouse = new Mouse(m_System, hwnd, exclusive);
		}
		return (m_Keyboard && m_Mouse);
	}

	bool DirectInput::UpdateDevices()
	{
		if(m_Mouse) m_Mouse->UpdateDevice();
		if(m_Keyboard)m_Keyboard->UpdateDevice();
		return true;
	}

	int DirectInput::KeyUp(unsigned int key)
	{
		if(m_Keyboard) 
			return m_Keyboard->ButtonUp(key);
		else
			return 0;
	}

	int DirectInput::KeyDown(unsigned int key)
	{
		if(m_Keyboard)
			return m_Keyboard->ButtonDown(key);
		else
			return 0;
	}

	int DirectInput::MouseButtonDown(unsigned int button)
	{
		if(m_Mouse) 
			return m_Mouse->ButtonDown(button);
		else
			return 0;
	}

	int DirectInput::MouseButtonUp(unsigned int button)
	{
		if(m_Mouse) 
			return m_Mouse->ButtonUp(button);
		else
			return 0;
	}

	POINT DirectInput::GetMousePos()
	{
		POINT p = {0, 0};
		if(!m_Mouse) return p;
		return m_Mouse->GetPosition();
	}

	long DirectInput::GetMouseWheelPos()
	{
		if(!m_Mouse) return 0;
		return m_Mouse->GetZPosition().y;
	}

	int DirectInput::ControllerButtonDown(unsigned int button)
	{
		return 0;
	}

	int DirectInput::ControllerButtonUp(unsigned int button)
	{
		return 0;
	}

	POINT DirectInput::GetLeftStickPos()
	{
		POINT p = {0,0};
		return p;
	}

	POINT DirectInput::GetRightStickPos()
	{
		POINT p = {0,0};
		return p;
	}

	void DirectInput::Shutdown()
	{
		if(m_Keyboard)
		{
			m_Keyboard->Shutdown();
			delete m_Keyboard;
			m_Keyboard = NULL;
		}
		if(m_Mouse)
		{
			m_Mouse->Shutdown();
			delete m_Mouse;
			m_Mouse = NULL;
		}
		if(m_System)
		{
			m_System->Release();
			m_System = NULL;
		}
	}

	//===================keyboard===========================

	Keyboard::Keyboard(LPDIRECTINPUT8 input, HWND hwnd)
	{
		if(input->CreateDevice(GUID_SysKeyboard, &m_Device, NULL) == DI_OK)
		{
			if(m_Device->SetDataFormat(&c_dfDIKeyboard) == DI_OK)
			{
				if(m_Device->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE) == DI_OK)
				{
					m_Device->Acquire();
				}
			}
		}
	}

	Keyboard::~Keyboard()
	{
	}

	bool Keyboard::UpdateDevice()
	{
		if(m_Device)
		{
			memcpy(m_OldKeys, m_Keys, sizeof(m_Keys));
			if(FAILED(m_Device->GetDeviceState(sizeof(m_Keys), (LPVOID)m_Keys)))
			{
				if(FAILED(m_Device->Acquire())) return false;
				if(FAILED(m_Device->GetDeviceState(sizeof(m_Keys), (LPVOID)m_Keys)))
				{
					return false; 
				}
				
			}
		}
		return false;
	}

	int Keyboard::ButtonUp(unsigned int key)
	{
		return (!(m_Keys[key] & 0x80) && m_Keys[key] != m_OldKeys[key]);
	}
	
	int Keyboard::ButtonDown(unsigned int key)
	{
		return m_Keys[key] & 0x80;
	}

	POINT Keyboard::GetPosition()
	{
		POINT p = {0, 0};
		return p;
	}
	POINT Keyboard::GetZPosition()
	{
		POINT p = {0, 0};
		return p;
	}

	void Keyboard::Shutdown()
	{
		if(m_Device)
		{
			m_Device->Unacquire();
			m_Device->Release();
			m_Device = NULL;
		}
	}

	//===================mouse==============================
	Mouse::Mouse(LPDIRECTINPUT8 input, HWND hwnd, bool exclusive)
	{
		DWORD flags;
		if(input->CreateDevice(GUID_SysMouse, &m_Device, NULL) == DI_OK)
		{
			if(m_Device->SetDataFormat(&c_dfDIMouse) == DI_OK)
			{
				if(exclusive) flags = DISCL_FOREGROUND | DISCL_EXCLUSIVE | DISCL_NOWINKEY;
				else flags = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
				if(m_Device->SetCooperativeLevel(hwnd, flags) == DI_OK)
				{
					m_Device->Acquire();
				}
			}
		}
	}

	Mouse::~Mouse()
	{
	}

	bool Mouse::UpdateDevice()
	{
		if(m_Device)
		{
			memcpy(&m_OldMouseState, &m_MouseState, sizeof(m_MouseState));
			if(FAILED(m_Device->GetDeviceState(sizeof(DIMOUSESTATE), &m_MouseState)))
			{
				if(FAILED(m_Device->Acquire())) return false;
				if(FAILED(m_Device->GetDeviceState(sizeof(DIMOUSESTATE), &m_MouseState))) return false;
			}

			m_Xpos += m_MouseState.lX;
			m_Ypos += m_MouseState.lY;
			m_Zpos += m_MouseState.lZ;
			return true;
		}
		return false;
	}

	POINT Mouse::GetPosition()
	{
		POINT p = { m_Xpos, m_Ypos};
		return p;
	}

	POINT Mouse::GetZPosition()
	{
		POINT p = { m_Zpos, m_Zpos};
		return p;
	}

	int Mouse::ButtonDown(unsigned int key)
	{
		return m_MouseState.rgbButtons[key] & 0x80;
	}
	
	int Mouse::ButtonUp(unsigned int key)
	{
		return (!(m_MouseState.rgbButtons[key] & 0x80) 
			&& m_MouseState.rgbButtons[key] != m_OldMouseState.rgbButtons[key]);
	}

	void Mouse::Shutdown()
	{
		if(m_Device)
		{
			m_Device->Unacquire();
			m_Device->Release();
			m_Device = NULL;
		}
	}

}